package org.zn.note.jdk.java8.Java8InAction;

import org.zn.note.jdk.java8.Java8InAction.bean.Apple;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

/**
 * 第3章 Lambda表达式
 * <p>
 * Lambda表达式是一种简洁的表达匿名函数的方式：它没有名称，但有参数列表、函数主体、返回类型、异常列表。
 * “函数”，不像“方法”那样属于某一个类。
 * Lambda表达式可以作为参数传递给方法，也可以存储在变量中。
 * <p>
 * Lambda基本语法：
 * 1、(parameter, parameter, ...) -> expression
 * 2、(parameter, parameter, ...) -> {statement; statement; ...}
 * (默认最后一个statement的执行结果，就是return值)
 * <p>
 * 函数式接口：接口里只有一个抽象方法
 * 例子：
 * {@link Comparator}、{@link Runnable}、{@link java.util.concurrent.Callable}
 * {@link java.awt.event.ActionListener}、{@link java.security.PrivilegedAction}
 * <p>
 * Lambda表达式允许你以内联的形式为函数式接口的抽象方法提供实现，并把整个表达式作为函数式接口的实例。
 * 和匿名内部类比，麻烦在哪？
 * 1、匿名内部类要指定实现的方法  2、匿名内部类要明确的实例化
 * Lambda表达式，最终的目的是以简洁的方式，获取到一个函数式接口的实例！
 * Runnable task = () -> System.out.println(Thread.currentThread().getName()); // 获取一个Runnable的实例
 * <p>
 * 函数描述符
 * 函数式接口的抽象方法的签名基本就是Lambda表达式的签名。这种抽象方法叫做“函数描述符”。
 * 签名(描述符)举例：
 * () --> void  没有传入参数，没有返回值
 * (Apple, Apple) --> int  传入两个Apple，返回int
 * 编译器检查：Lambda表达式签名 = 函数式接口抽象方法签名
 * （1.8新增标识函数式接口的注解 {@link FunctionalInterface}，如果标注了，编译器有检查）
 * <p>
 * 1.8新增函数式接口
 * java.util.function 包下，引入了一些函数接口：
 * {@link java.util.function.Predicate}  boolean test(T t);
 * {@link java.util.function.Consumer}   void accept(T t);
 * {@link java.util.function.Function}   R apply(T t);
 * （Java类型：引用类型如Integer、原始类型int。装箱：int --> Integer，拆箱：Integer --> int）
 * （上面的泛型都是支持引用类型的，虽然可以自动装箱，但是自动装箱的本质是包裹，要更多内存）
 * 提供对应的原始类型函数接口：
 * 如 {@link java.util.function.IntPredicate} boolean test(int value);
 * <p>
 * 关于Lambda使用局部变量
 * 其实和匿名内部类对变量的要求一致：这个局部变量不能再变。（从1.8开始，不非要final的，只要这个变量不变就行）
 * 实例变量在堆上，各个线程都可以访问到，所以直接访问那个变量就可以了。
 * 而方法内的局部变量在方法栈上，假如不在一个线程里，是无法访问的。所以就复制了一份，也就要求这个变量不能再变！
 * Lambda仅仅是匿名内部类的简单写法，“语法糖”。
 * <p>
 * 关于闭包(closure)
 * 是一个更大的概念：定义在函数中的函数，可以无限制访问函数中的变量。
 * Lambda算是闭包，但不完全是，因为它访问它所在方法的变量时是有限制的，这个变量不能在变了。
 */
class Ch3 {
    interface Animal {
        boolean hasFourFeet(Animal a);

        default int getFeet() {
            return 4;
        }
    }

    private void lambda() {
        // 获取一个接口的实例
        Animal animal1 = (Animal a) -> 4 == a.getFeet();
        // 类型推断
        Animal animal2 = (a) -> 4 == a.getFeet();
        // 方法引用
        List<Apple> inventory = new ArrayList<>();
        inventory.sort(Comparator.comparingInt(Apple::getWeight));
    }
}
